
\chapter{RISCO}
\label{c:risco}

Como foi observado no capítulo \ref{c:sistemas_embarcados}, o uso de componentes
terceirizados é uma fase crucial do projeto de sistemas embarcados. A escolha
dos componentes com as características certas influencia diversos aspectos do
projeto. Tais componentes necessitam ser projetados tendo em vista todos os
requisitos inerentes a esses sistemas. Em geral, têm no mínimo o seu tamanho,
custo/benefício e consumo de energia otimizados. Consequentemente, um campo
natural de pesquisa na academia é a especificação, projeto e construção de
componentes de hardware ou software otimizados para sistemas embarcados.

Os trabalhos de \citeonline{vahid_spec_art} e \citeonline{rt_uml} mostram
esforços em direção à padronização de técnicas de modelagem de sistemas
embarcados. Existem também muitas opções de sistemas operacionais destinados a
sistemas embarcados com requisitos de tempo real, tais como o QNX
\cite{qnx_site} e o RT-Linux \cite{rt_linux}. Além de componentes de software, o
projeto de componentes de hardware para sistemas embarcados também é bastante
explorado: \citeonline{mips_embedded}, por exemplo, apresentam um
microprocessador projetado para SE's, baseado no MIPS. Como visto na seção
\ref{ss:ip_reuse}, o uso de componentes terceirizados, pré-fabricados ou não,
traz vantagens significativas ao projeto de um SE, tais como a diminuição do seu
custo ou do tempo de protótipo ou de produção. Isto reforça a importância de se
considerar atentamente a escolha de um processador para um SE. Em geral, existem
3 opções:

\begin{itemize}
\item É possível projetar o sistema por si próprio, com uma equipe de
desenvolvimento interna. Isto é, desenvolver um processador dedicado à tarefa em
questão, projetado do início ao fim. Isto resulta em um projeto otimizado, um
processador de alta performance para a sua função designada. Entretanto, aumenta
muito o tempo de projeto e de protótipo. Como vantagem, o seu custo de produção
por unidade pode ser mais competitivo com relação às outras opções, caso um
número suficiente de unidades sejam produzidas.

\item Existem empresas que vendem o projeto de um processador sob a forma de IP:
em geral, uma especificação completa do processador em uma linguagem formal de
descrição de hardware (ex: VHDL). Esta escolha aumenta o custo de projeto, porem
não aumenta o seu tempo. Além disto, esta é uma opção flexível pois permite que
a especificação do processador seja modificada para atender a certos requisitos
específicos da aplicação de um SE.

\item Por fim, a equipe pode optar por utilizar um processador de propósito
geral ``de prateleira''. Isto é, um processador pré-fabricado. Esta opção não
impacta o custo de projeto, porém em geral aumenta o custo total de uma unidade
do produto. Além disto, o projeto terá que ser adaptado de acordo com a
interface do processador escolhido.
\end{itemize}

Neste contexto, vê-se que uma especificação aberta de um microprocessador
simples e eficiente para sistemas embarcados é uma boa opção. Pode-se utilizar a
sua especificação em um projeto particular, obedecendo a restrições de
licenciamento, obtendo as melhorias de tempo e flexibilidade mencionadas acima.
Há a opção de utilizá-lo do modo como ele é disponibilizado, semelhantemente a
utilização de um processador sob a forma de IP proprietária, ou pode-se
modificar a especificação original para produzir um processador customizado,
específico a uma determinada aplicação (ASIC). Na literatura existem diversos
exemplos de desenvolvimento de especificações abertas de hardware
\cite{open_hardware_ex1}, incentivando a iniciativa comum
sob a legenda de \emph{Open Hardware} \cite{open_hardware}.

O processador \textbf{RISCO} \cite{risco_tese} foi criado pelo grupo de
microeletrônica da UFRGS com o objetivo de adquirir um projeto próprio de
processador, assim como uma aprofundação de conhecimentos sob o assunto.
Entretanto, além disso, ele também se encaixa perfeitamente como um processador
de SE, como foi detalhado em \ref{s:detalhes_risco}.

Nas seções a seguir são apresentados argumentos em relação à validade da
utilização do RISCO no âmbito de sistemas embarcados e sistemas de tempo real,
salientando as vantagens e desvantagens das decisões de projeto que foram
tomadas no seu desenvolvimento.


\section{Detalhes do projeto}
\label{s:detalhes_risco}

O RISCO é um projeto antigo (\citeyear{risco_tese}) de um micro-processador
RISC. Seu projeto teve como objetivo a simplicidade de implementação e
sintetização, facilidade de simulação e baixo consumo de energia. Tais
características o fazem um bom candidato para implantação nos mais diversos
sistemas embarcados.

\abrv[CMOS -- Complementary metal–oxide semiconductor]

Os processadores que seguem a filosofia RISC apresentam um conjunto de
instruções menor, mais simples e altamente otimizado, em vez de um grande
conjunto de instruções complexas para as mais diversas situações como nos CISC,
podendo acarretar em um aumento de performance significativo. Algumas famílias
de processadores RISC bem conhecidas no mercado atual são a Alpha AXP, ARM,
MIPS, PowerPC e \mbox{SPARC \cite{risc_processors}}.

Em geral, como discutido em \cite{patterson_book, es_architecture_guide}, os
processadores RISC necessitam de mais instruções do que máquinas CISC para
executar uma mesma tarefa, isto é, apresentam uma menor densidade de código.
Entretanto, os processadores RISC em si tem uma implementação mais simples e
previsível, contendo somente instruções básicas, que cobrem 90\% das instruções
utilizadas por programas reais \cite{risco_tese}. O uso de poucas instruções,
cada qual com uma funcionalidade não complexa, faz com que a execução de uma
única instrução seja bastante eficiente. Isto é, o ciclo do relógio do
processador pode ser reduzido. Além disso, a regularidade do conjunto
de instruções de um processador RISC, aliado aos conceitos de ortogonalidade
empregados, fazem com que seja possível a implementação de estágios de
pipelines mais bem definidos e divididos, com um melhor comportamento quando
comparados a um processador CISC. 

Outras características de um processador RISC são: formato uniforme de
instruções, resultando em um circuito de baixa complexidade para a sua
decodificação; uso de registradores de propósito geral idênticos, podendo ser
utilizados sem restrições em todas as instruções; somente modos de
endereçamento simples, com operações mais complexas necessitando serem
realizadas com mais de uma instrução; baixo consumo de energia devido a uma
menor complexidade do circuito interno. 

Devido a estas características, os processadores RISC são a preferência, hoje
em dia, no projeto de sistemas embarcados. Em especial, o ótimo custo/benefício
dos seus processadores, aliado a eficiência no consumo de energia são bastante
atrativos para as empresas deste ramo. Os processadores RISC dominam quase que
completamente o mercado de celulares e tablets. Devido a grande quantidade de
tais dispositivos, a família RISC é largamente mais utilizada do que os
processadores CISC \cite{es_architecture_guide} no conjunto de todos os
dispositivos computacionais existentes, embora tenha uma baixa penetração no
mercado de computadores pessoais, dominado pela família de processadores
\mbox{x86 \cite{x86_processor}}.

Atualmente, o RISCO é distribuído sob duas formas. É possível obter uma
especificação do processador como uma modelagem em alto nível, utilizando a
ferramenta SystemC \cite{systemc}, ou como uma especificação sintetizável de
hardware na linguagem VHDL \cite{vhdl}. Ambas as modelagens já foram testadas
em outros trabalhos. Algumas das características do RISCO são:

\begin{itemize}
\item Dados e instruções são palavras de 32 bits, e um byte da memória
principal pode ser endereçado diretamente por uma palavra. Consequentemente,
suporta a utilização de até $2^{32}$ bytes de memória, o equivalente a 4GB,
quando programado em modo real. Em modo protegido, esta quantidade seria menor.

\item Comunica-se com a memória através de um barramento multiplexado de 32
bits, utilizado tanto para dados como para endereços.

% \item Contêm 32 registradores, incluindo os usuais \abrv[PC -- Program
% Counter]{PC}, \abrv[SP -- Stack Pointer]{SP}, \abrv[PSTW -- Processor Status
% Word]{PSTW} e R0.

\item Apresenta um pipeline de instruções tradicional RISC com 3 estágios:
(i) decodificação e busca de operandos, (ii) realização da operação e
(iii) escrita dos resultados.

\end{itemize}

O seu projeto simples corresponde a uma arquitetura RISC bastante eficiente e de
baixo consumo. Isto o torna uma possível opção comercial viável para uso em
sistemas embarcados. Os detalhes da arquitetura interna do RISCO, relativos a
sua especificação oficial definida em \cite{risco_tese} fogem o escopo deste
trabalho. Entretanto, certos detalhes deste tipo são mencionados ao longo do
texto, caso sejam diretamente relevantes para a definição da semântica das
instruções do RISCO.


\section{Conjunto de instruções}
\label{s:risco_instrucoes}

Seguindo as tradições de projetos RISC, o conjunto de instruções do RISCO é
composto por instruções de até 3 endereços, sendo um destino e dois operandos.
Os operandos são sempre constantes incluídas na palavra ou identificadores para
um dos registradores da UCP. Apresenta 3 formatos de instruções diferentes,
porém todos com o mesmo tamanho. As instruções são classificadas em: instruções
lógicas e aritméticas, saltos, acesso a memória (no esquema \textit{load} e
\textit{store}), e chamada de sub-rotinas. O projeto das instruções enforça os
princípios já conhecidos de ortogonalidade e simetria das operações de
processadores que seguem a filosofia RISC. Isto é, as instruções podem utilizar
todos os tipos de dados e todos os modos de endereçamento.

\begin{figure}[htb]
  \centering
  \includegraphics[scale=0.6]{images/instrucao-divisao_opcode}
  \textsf{\caption{Formato base das instruções RISCO
          \label{fig:formato_base}}}
\end{figure}

Uma instrução RISCO é uma palavra de 32bits acessada na memória principal.
Todos os 3 formatos de instrução seguem o modelo apresentado na figura
\ref{fig:formato_base}. Os 8 bits que vão de 24 a 31 da palavra identificam
unicamente a instrução que será executada, junto com o \emph{modificador de
status}. Os bits restantes, da posição 0 a 23, indicam quais são os operandos e
o destino da instrução, na tradição dos códigos de 3 endereços. A partir do
campo dos operandos, o decodificador da UCP determina 3 valores, DST, FT1 e FT2,
a serem utilizados pela instrução. DST sempre é um identificador de registrador,
enquanto FT1 e FT2 podem ser registradores ou constantes, como veremos mais
adiante. A instrução, portanto, pode ser vista como uma função de 3 parâmetros:
\mbox{\texttt{instrucao(DST, FT1, FT2)}}.

\abrv[PSW -- Processor Status Word]

Os campos T1 e T0 indicam o tipo da instrução, que pode ser: aritmético-lógica
(00), salto (01), acesso a memória (10) ou chamada de sub-rotina (11). Os
campos C4 a C0 indicam a instrução específica dentro do grupo T1-T0. O campo
APS é o bit indicador da modificação de status. Caso seja 1, após a realização
da operação indicada pela instrução, a UCP atualiza o seu \emph{registrador de
status}, PSW, baseando-se nos valores das operações. 

\begin{figure}[htb]
  \centering
  \includegraphics[scale=0.7]{images/instrucao-operandos}
  \textsf{\caption{Os 3 formatos de identificação dos operandos RISCO
          \label{fig:formato_operandos}}}
\end{figure}

Os bits 0 a 23, que determinam os operandos e o destino da instrução, tem 3
formatos diferentes, conforme a figura \ref{fig:formato_operandos}. Nesta
figura, os campos Rdst, Rft1 e Rft2, de 5 bits cada, indicam um dos
registradores dentro dos 32 possíveis. $K_{17}$ e $K_{11}$ são constantes
numéricas com sinal, de 17 e 11 bits, representadas em complemento de 2. A
partir destes 3 formatos de campos na instrução, existem 5 interpretações
diferentes para os valores DST, FT1 e FT2 mencionados acima, de acordo com a
tabela \ref{tab:formato_operandos}.

\begin{table}[htb!]
\begin{center}
\begin{tabular}{ c | c | c | c | c | c | c }
  & \textbf{DST} & \textbf{FT1} & \textbf{FT2} & F1 & F0 & SS2 \\
  \hline
  1 & Rdst & Rft1 & Rft2 & 0 & 0 & 0 \\
  2 & Rdst & Rft1 & $K_{11}$ & 0 & 0 & 1 \\
  3 & Rdst & R0 & $K_{17}$ & 0 & 1 & x \\
  4 & Rdst & Rdst & $K_{17}[15:0]$ \& $K_{17}[16]$ * 16 & 1 & 0 & x \\
  5 & Rdst & Rdst & $K_{17}$ & 1 & 1 & x \\
\end{tabular}
\end{center}
\caption{Interpretação dos operandos RISCO \label{tab:formato_operandos}}
\end{table}

Note que os 5 formatos são identificados a partir dos valores nos campos F1, F0
e SS2. Em todos os 5, o parâmetro DST sempre é o registrador indicado por Rdst.
Os casos interessantes são: no formato 3, FT1 é um parâmetro implícito sempre
apontando para o registrador R0; nos formatos 4 e 5, FT1 é sempre Rdst; no
formato 4, FT2 é a concatenação dos bits 0 a 15 de $K_{17}$ com o seu bit mais
significativo replicado 16 vezes. Variações do formato 4 são comuns em
arquiteturas RISC, como o MIPS \cite{patterson_book}, onde são utilizadas para
carregar uma sequência de bits nos bits mais significativos de um registrador,
utilizando somente uma instrução.

Em geral, os 32 registradores do RISCO são idênticos. Os casos especiais são:

\abrv[PC -- Program Counter]

\begin{itemize}
  \item \textbf{R00}: Sempre guarda o valor 0, e operações de escrita não tem
  efeito\footnote{O único efeito possível é a atualização do registrador PSW,
  caso o bit APS da instrução seja 1. Isto é comumente utilizado para realizar
uma comparação rápida entre dois valores.} quando ele é o destino.
  
  \item \textbf{R01}: Guarda a palavra de estado do processador, PSW. Contêm
  bits indicando propriedades do resultado da última operação que teve o bit APS
  setado, sendo eles: N (negativo), O (overflow), Z (zero) e C (carry). Não pode
  ser escrito por software.
  
  \item \textbf{R31}: Guarda o valor do contador de programa (PC). Pode ser
  escrito explicitamente por uma instrução, ou implicitamente em uma instrução
  de salto.
\end{itemize}

O apêndice \ref{c:apendice_instrucoes} contém uma descrição do conjunto
completo de instruções do processador RISCO. Aqui foram incluídos somente
alguns comentários.

As decisões de projeto do RISCO com relação ao seu pipeline interno
introduziram certas dificuldades para a programação do processador. Todas as
instruções de salto e chamada de subrotina apresentam um atraso de 1 instrução.
Isto é, a instrução logo após o salto sempre é executada, mesmo quando o salto
for tomado. O programador deve atentar e inserir uma instrução adequada neste
espaço, ou então uma instrução que não tenha efeitos. 

O conjunto de operações aritmético-lógicas é bastante extenso e completo. Todas
as operações mais comuns estão presentes, com duas exceções significativas: as
operações de multiplicação e divisão. Esta decisão foi tomada para simplificar
o projeto da unidade lógico-aritmética do RISCO, com a desvantagem de impor uma
penalidade na performance dos programas compilados para esta arquitetura, como
será visto no capítulo \ref{c:risco_llvm}. As operações cujos mnemônicos
terminam em ``c'' utilizam o bit C (carry) do registrador PSW nas operações,
possibilitando a utilização de técnicas interessantes para a aritmética com
inteiros de mais de 32 bits. Além dessas instruções, existem diversas variações
de deslocamento e rotações que são úteis na manipulação de inteiros com menos de
32 bits. 

As instruções de acesso a memória utilizam o modelo tradicional de \emph{load}
e \emph{store} do RISC. O RISCO também incluiu variantes destas duas instruções
para os casos comuns em que há um incremento ou decremento de uma variável
utilizada no endereçamento da memória. Incrementos antes e depois do
endereçamento são representados pelos sufixos ``\texttt{pri}'' e
``\texttt{poi}'', enquanto decrementos após o endereçamento são identificador
por ``\texttt{pod}''. São situações comuns em códigos que manipulam arranjos.

As instruções de salto são implementadas como somas condicionais. Isto é, são
instruções \texttt{add} que só são executadas caso certo bit do registrador PSW
esteja ligado ou não. O programador precisa ter o cuidado de especificar que o
operando DST seja o registrador R31, e que a soma FT1 + FT2 resulte no endereço
desejado.

A instrução de chamada de sub-rotina do RISCO (\texttt{sr}), e suas variantes
condicionais, determinam o endereço destino como nas instruções de salto, porém
também guardam o valor atual de R31 na posição especificada pelo registrador
DST (que neste caso não equivale ao destino). O programador precisa atentar
para que DST-1 seja um espaço de memória válido e esteja intacto quando a
subrotina retornar. Note que não há uma instrução explícita para o retorno da
sub-rotina. Entretanto, dependendo da escolha da convenção de chamada, ela pode
ser derivada a partir de \texttt{ldpoi}. Isto será discutido em detalhe no
capítulo \ref{c:risco_llvm}.


\section{Plataforma de desenvolvimento}

Como foi visto na seção \ref{ss:compilacao_evolucao}, os processos
tradicionais de desenvolvimento de software para sistemas embarcados necessitam
de um conjunto mínimo de ferramentas específicas para a plataforma em questão. 

Além disto, não é suficiente contar apenas com ferramentas que suportem o
desenvolvimento de software em linguagem de montagem. Por exemplo, apesar de se
tratar de uma arquitetura RISC, o conjunto de instruções do RISCO é, em certos
pontos, muito simplista para a programação manual do dispositivo. Isto é,
algumas decisões ligadas à filosofia RISC dificultaram a produção direta de
código assembly para este processador:

\begin{itemize}
\item Não há instruções para multiplicação e divisão. O programador deve
codificar uma função equivalente ou utilizar uma já existente.

\item Uso excessivo de ortogonalidade nas instruções faz com que algumas
combinações de endereçamento sejam válidas do ponto de vista sintático, porém
inválidas semanticamente. É possível fazer uso abusivo dos modos de
endereçamento para produzir uma instrução que não faça sentido ou que não seja
o desejado.

\item Carregar uma constante de 32 bits em um registrador utiliza duas
instruções, ao invés de uma instrução de tamanho estendido, pois o RISCO usa um
esquema de tamanho fixo.

\item As instruções de salto que utilizam endereçamento direto estão limitadas
a um salto cujo destino seja representado por uma constante de 17 bits. Isto é,
em programas com mais de 128 KB já não é mais possível realizar um salto direto
para uma determinada posição. Saltos maiores com endereçamento direto só
são possíveis quando utiliza-se mais de uma instrução.
\end{itemize}

Em \ref{s:software_embarcado} discutimos como já é bem estabelecido o fato de
que, até no contexto de sistemas embarcados, a programação utilizando linguagens
de alto nível apresenta inúmeras vantagens com relação à programação direta em
linguagem de máquina. As decisões minimalistas presentes no projeto do RISCO,
explicadas acima, simplificaram o projeto do processador (e também a sua
eficiência e consumo de energia), porém aumentaram a dificuldade de programação
na linguagem de máquina do RISCO. Além desta barreira de aprendizado, a falta de
suporte a linguagens estruturadas inibe o uso sério do processador como uma
opção prática para a construção de um sistema embarcado.

Para qualquer uso real do processador RISCO, assim como para facilitar a
continuidade das pesquisas acadêmicas que o envolvam \cite{hwsw_parallelism}, é
clara a necessidade de um conjunto de ferramentas que facilitem a programação
deste processador, suportando uma linguagem que apresente suporte às abstrações
de software estruturado.

Até o momento da conclusão deste trabalho, o desenvolvimento de software para
este processador se dá somente na academia. A tese de mestrado de
\citeonline{risco_tese}, contendo a primeira descrição do RISCO, apresenta um
anexo com uma descrição funcional do processador em um dialeto de C (HDC). Desde
essa primeira especificação, foram desenvolvidas versões do RISCO em SystemC e
VHDL. Com relação ao suporte a programação para o processador, havia somente um
montador de linguagem de montagem para execução do programa junto ao modelo
SystemC.


\subsection{Ferramentas}

O objetivo principal deste trabalho foi a construção de um conjunto
de ferramentas para o desenvolvimento de software para o processador RISCO em
uma linguagem de alto nível. Além de suplantar e/ou estender as
ferramentas atuais existentes para o RISCO, espera-se que este ambiente seja
suficientemente maduro e robusto para que o processador ganhe uma visibilidade
maior como uma opção viável para o desenvolvimento de sistemas embarcados. Todo
o software resultante está disponível sob a forma de código livre, com a licença
LGPL. Ele pode ser obtido em \cite{risco_site}. O conjunto de ferramentas é
divido em camadas, de acordo com quais etapas dos fluxogramas nas figuras
\ref{fig:fluxo_desenvolvimento} e \ref{fig:fluxo_execucao} cada uma delas
representa.

\begin{itemize}
  \item \emph{Plataforma base}: São as
  ferramentas que habilitam o  desenvolvimento e a execução de software escrito
  na linguagem de montagem do  RISCO. São o \textbf{risco-as} e o
  \mbox{\textbf{risco-sim}}.
  
  \item \emph{Compilador}: é o módulo RISCO para o
  projeto LLVM, sob o nome de  \textbf{risco-llvm}. Com ele, é possível
  aproveitar as ferramentas de compilação disponibilizadas pelo LLVM, incluindo
  o compilador de C, C++ e Object-C.
  
  \item \emph{Análise de código}: São os
  componentes que permitem analisar os grafos de fluxo de execução de um código
  RISCO. São disponibilizados como a ferramenta \textbf{risco-cfg}.
\end{itemize}

Os próximos capítulos discutem o projeto e o desenvolvimento desses módulos.
